#-*- encoding: utf-8 -*-

###################
#
# server.py
#
# autor: Rafael Pinheiro
#
# descrição: Servidor HTTP simples escrito em python utilizando threads
#
###################

import socket, os, mimetypes, sys
from threading import Thread
from os import path

# variáveis globais
host = ''
port = 5555
wwwdir = os.getcwd() + '/www'
serverdir = os.getcwd() + '/server_pages'
logfile = os.getcwd() + '/log'
sys.stderr = open(logfile, 'a')

# Classe para a thread que responde a cada requisição
class server_thread(Thread):
	def __init__(self, num, csock, caddr):
		''' Construtor: recebe o número da thread(num), o socket(csock) e o endereço do cliente(caddr).
			Imprime: "Começando thread (num) |endereço: (caddr)" '''
		self.num = num
		self.csock = csock
		self.caddr = caddr
		Thread.__init__(self)
		print "Começando thread", self.num, "|endereço:", self.caddr[0]
	def run(self):
		'''Método que roda a thread quando o método start() é chamado.
			Imprime: "caminho: " + caminho requisitado
			Imprime: "Terminando thread " + número da thread '''
		
		#criando um arquivo(para leitura) a partir do socket e lê a primeira linha pegando o caminho
		self.cfile = self.csock.makefile('r', 0) 
		self.line = self.cfile.readline().strip() 
		self.path = self.line.split()[1]
		#fecha o arquivo
		self.cfile.close()
		#imprime o caminho na tela
		print "caminho:", self.path
		#declara uma flag para indicar se achou a página
		achou = False
		#verifica se o caminho existe
		if path.exists(wwwdir + self.path):
			achou = True
			#transforma o caminho em um caminho absoluto
			self.path = wwwdir + self.path
			#se o caminho for um diretório 
			if path.isdir(self.path):
				#se tiver um index.html dentro
				if path.exists(self.path + '/index.html'):
					#completa o caminho com o index
					self.path += '/index.html'
				#se não tiver o index dentro
				else:
					achou = False
					#retorna a página do erro 404
					self.path = serverdir + '/404.html'
			
				
		#se o caminho não existe
		else:
			#Procura o endereço no diretório do servidor
			if path.exists(serverdir + self.path):
				self.path = serverdir + self.path
			else:
				#se não achar mostra a página de erro 404
				self.path = serverdir + '/404.html'
				
		#criando um arquivo(para escrita) a partir do socket
		self.cfile = self.csock.makefile('wb') 
		#se achou...
		if achou:
			#escreve no arquivo respondendo para o cliente
			self.cfile.write('HTTP/1.1 200 OK\r\n')
		#se não achou...
		else:
			#escreve no arquivo respondendo para o cliente com o erro 404
			self.cfile.write('HTTP/1.1 404 Not Found\r\n')
		#informa o tamanho do arquivo
		self.cfile.write('Content-Length: %d\r\n' %path.getsize(self.path))
		#fecha o cabeçalho HTTP do documento
		self.cfile.write('\r\n')
		#abri o arquivo requisitado
		self.f = open(self.path, 'rb')
		#lê o conteúdeo do arquivo
		self.cont = self.f.read()
		#fecha o arquivo
		self.f.close()
		try:
			#escreve o arquivo requisitado no caminho para o arquivo do socket enviando para o cliente
			self.cfile.write(self.cont)
		#se o cliente não aceitar o envio...
		except:
			#cancela
			pass
		#fecha o arquivo do socket
		self.cfile.close()
		try:
			#manda o sinal para terminar a conexão para o cliente
			csock.shutdown(socket.SHUT_WR)
		#se o cliente não estiver conectado...
		except:
			#cancela
			pass
		#fecha a conexão
		csock.close() 
		#imprime a mensagem sinalizando o fim da thread
		print "Terminando thread", self.num
		
			

#criando um socket da família IPv4(AF_INET) e do tipo conexão de stream de bytes por TCP
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
#configurando o socket
c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

#conecta o socket
c.bind((host, port)) 
#informa que está servindo
print "Servindo em %s:%d" %(socket.gethostname(), port)

#manda o servidor escutar
c.listen(1) 

try:
	thread = 1
	#loop infinito
	while 1:
		#aceita a conexão
		csock, caddr = c.accept()
		#inicia uma nova thread pra servir a requisição
		server_thread(thread, csock, caddr).start()
		thread+=1

except KeyboardInterrupt:
	print "\r\nServidor parado pelo usuário..."
